package vip.xiaonuo.bi.core.datasource.util;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.fastjson.JSONArray;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.bi.modular.dataset.dto.PreviewDto;
import vip.xiaonuo.bi.modular.datasource.dto.Colunm;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static vip.xiaonuo.bi.core.datasource.util.ColumnUtils.convertColumnDataByTypeListData;

/**
 * @auther: 顾育司
 * @Description excel 导入工具类
 * @date: 2024/1/9
 */
public class ExcelImportUtils {

    @Slf4j
    public static class ExcelDataListener extends AnalysisEventListener<Map<Integer, String>> {
        /**
         * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
         */
        private static final int BATCH_COUNT = 5;
        // 存储自定义表头
        private Map<Integer, String> headers = new LinkedHashMap<>();

       // 数据收集
//        private  List<Map<String, String>> dataList = new ArrayList<>();
        private  List<List<String>> dataList = new ArrayList<>();


        public List<List<String>>  getDataList() {
            return dataList;
        }


        public List<String> getColumns() {
            return new ArrayList<>(headers.values());
        }

        /**
         * 这里会一行行的返回头
         *
         * @param headMap
         * @param context
         */
        @Override
        public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {

            headMap.forEach((p,v)->{
                headers.put(v.getColumnIndex(),v.getStringValue());
            });
        }

        @Override
        public void invoke(Map<Integer, String> data, AnalysisContext context) {
//            Map<String, String> dataMap = new LinkedHashMap<>();
//            data.forEach((p,v)->{
//                dataMap.put(headers.get(p),v);
//            });
//            dataList.add(dataMap);
            List<String> list = new ArrayList<>();
            data.forEach((p,v)->{
                list.add(v);
            });
            dataList.add(list);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            saveData();
        }

        /**
         * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
         *
         * @param exception
         * @param context
         * @throws Exception
         */
        @Override
        public void onException(Exception exception, AnalysisContext context) {
            log.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
            // 如果是某一个单元格的转换异常 能获取到具体行号
            // 如果要获取头的信息 配合invokeHeadMap使用
            if (exception instanceof ExcelDataConvertException) {
                ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
                log.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                        excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
            }
        }


        /**
         * 加上存储数据库
         */
        private void saveData() {
            // 暂不处理
        }
    }

    @SneakyThrows
    public static PreviewDto uploudExcel(MultipartFile file, String colInfoJson) {

        ExcelImportUtils.ExcelDataListener excelDataListener = new ExcelImportUtils.ExcelDataListener();

        EasyExcel.read(file.getInputStream(), excelDataListener)
                .sheet()//默认读取第一个sheet
                .headRowNumber(1)//定义表头行
                .doReadSync();
        // 获取数据集
        List<List<String>> dataList = excelDataListener.getDataList();
        System.out.println(dataList);
        // 获取表头
        List<String> columns = excelDataListener.getColumns();
        Map<String, String> tableColumn = DorisUtils.getTableColumn(columns);

        List<Colunm> cols = new ArrayList<>();
        // 如果用户改变列类型返回值
        if(ObjectUtil.isNotEmpty(colInfoJson)){
            // String解析成Map
            cols = JSONArray.parseArray(colInfoJson,Colunm.class);
            Map<String, String> columnTypeMap = cols.stream().collect(Collectors.toMap(k -> k.getName(), v -> v.getType(), (k, v) -> k));
            // 改变数据
            dataList = convertColumnDataByTypeListData(dataList, columns, columnTypeMap);
        }else{
            Map<String, String> finalColumnType =   ColumnUtils.getColumnType(dataList, columns);
            ArrayList  list = new ArrayList<>();
            columns.forEach(item->{
                Colunm column = new Colunm();
                column.setName(item);
                column.setType(finalColumnType.get(item));
                list.add(column);
            });
            cols.addAll(list);
        }


        PreviewDto previewDto = new PreviewDto();
        previewDto.setColums(cols);
        previewDto.setData(dataList);
//        previewDto.setLoadId(excelUUID);
        return  previewDto;
    }

}
